package org.baicaixiaozhan.tenet.time;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Date;

/**
 * 时间 工具集
 *
 * @author baicaixiaozhan
 * @since 1.0.0
 */
public final class DateTimes {

    private DateTimes() {
        throw new AssertionError();
    }

    public static DateTimeFormatter getDateTimeFormatter(String formatter) {
        return DateTimeFormatter.ofPattern(formatter);
    }

    /**
     * 获取当前时间到第二天凌晨00：00 相隔多少分钟
     *
     * @return 分钟数
     */
    public static Long getMinuteUntilNextDay() {
        return ChronoUnit.MINUTES.between(getCurrLocalDateTime(), atStartOfNextDay());
    }

    /**
     * 获取当前时间到第二天凌晨00：00 相隔多少秒钟
     *
     * @return 秒钟数
     */
    public static Long getSecondsUntilNextDay() {
        return ChronoUnit.SECONDS.between(getCurrLocalDateTime(), atStartOfNextDay());
    }

    /**
     * 获取第二天凌晨 00:00
     *
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime atStartOfNextDay() {
        return getCurrLocalDate().plusDays(1).atStartOfDay();
    }

    /**
     * 获取当前时间到第二年凌晨00：00 相隔多少分钟
     *
     * @return 分钟数
     */
    public static Long getMinuteUntilNextYear() {
        return ChronoUnit.MINUTES.between(getCurrLocalDateTime(), getCurrLocalDate().plusYears(1).atStartOfDay());
    }

    /**
     * 返回当前的日期
     */
    public static LocalDate getCurrLocalDate() {
        return LocalDate.now();
    }

    /**
     * 返回当前时间
     */
    public static LocalTime getCurrLocalTime() {
        return LocalTime.now();
    }

    /**
     * 返回当前日期时间
     */
    public static LocalDateTime getCurrLocalDateTime() {
        return LocalDateTime.now();
    }

    /**
     * 日期相隔秒
     */
    public static Long hoursBetween(LocalDateTime startDateTime, LocalDateTime endDateTime) {
        return datetimeBetween(ChronoUnit.HOURS, startDateTime, endDateTime);
    }

    /**
     * 日期相隔天数
     */
    public static Long daysBetween(LocalDate startDate, LocalDate endDate) {
        return dateBetween(ChronoUnit.DAYS, startDate, endDate);
    }

    /**
     * 日期相隔周数
     */
    public static Long weeksBetween(LocalDate startDate, LocalDate endDate) {
        return dateBetween(ChronoUnit.WEEKS, startDate, endDate);
    }

    /**
     * 日期相隔月数
     */
    public static Long periodMonths(LocalDate startDate, LocalDate endDate) {
        return dateBetween(ChronoUnit.MONTHS, startDate, endDate);
    }

    /**
     * 日期相隔年数
     */
    public static Long yearsBetween(LocalDate startDate, LocalDate endDate) {
        return dateBetween(ChronoUnit.YEARS, startDate, endDate);
    }

    private static Long dateBetween(ChronoUnit unit, LocalDate startDate, LocalDate endDate) {
        return unit.between(startDate, endDate);
    }

    private static Long datetimeBetween(ChronoUnit unit, LocalDateTime startDate, LocalDateTime endDate) {
        return unit.between(startDate, endDate);
    }

    /**
     * 是否当天
     */
    public static Boolean isToday(LocalDate date) {
        return getCurrLocalDate().equals(date);
    }

    /**
     * 获取当前毫秒数
     */
    public static Long toEpochMilli(LocalDateTime dateTime) {
        return dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    /**
     * 判断是否为闰年
     */
    public static Boolean isLeapYear(LocalDate localDate) {
        return localDate.isLeapYear();
    }

    /**
     * {@link LocalDate} to {@link Date}
     */
    public static Date toDate(LocalDate localDate) {
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = localDate.atStartOfDay().atZone(zone).toInstant();
        return Date.from(instant);
    }

    /**
     * {@link LocalDateTime} to {@link Date}
     */
    public static Date toDate(LocalDateTime localDateTime) {
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = localDateTime.atZone(zone).toInstant();
        return Date.from(instant);
    }

    /**
     * {@link LocalTime} to {@link Date}
     */
    public static Date toDate(LocalTime localTime) {
        LocalDate localDate = LocalDate.now();
        LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = localDateTime.atZone(zone).toInstant();
        return Date.from(instant);
    }

    /**
     * {@link Date} to {@link LocalTime}
     *
     * @param date 目标时间对象
     * @return {@link LocalDateTime}
     */
    public static LocalTime toLocalTime(Date date) {
        Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
        return localDateTime.toLocalTime();
    }

    /**
     * {@link Date} to {@link LocalDateTime}
     */
    public static LocalDateTime toLocalDateTime(Date date) {
        Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        return LocalDateTime.ofInstant(instant, zone);
    }

    /**
     * {@link Date} to {@link LocalDate}
     */
    public static LocalDate toLocalDate(Date date) {
        Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
        return localDateTime.toLocalDate();
    }

    /**
     * {@link Date} 格式化成 {@link String} （线程安全）
     */
    public static String format(Date date, String pattern) {
        return toLocalDateTime(date).format(getDateTimeFormatter(pattern));
    }

    /**
     * {@link LocalDateTime} 格式化成 {@link String}
     */
    public static String format(LocalDateTime localDateTime, String pattern) {
        return localDateTime.format(getDateTimeFormatter(pattern));
    }

    /**
     * {@link LocalDate} 格式化成 {@link String}
     */
    public static String format(LocalDate localDate, String pattern) {
        return localDate.format(getDateTimeFormatter(pattern));
    }

}
